package com.suemi.missile.common.mql.query;

import com.suemi.missile.common.mql.domain.*;
import com.suemi.missile.common.mql.exception.MqlParseException;
import com.suemi.missile.common.mql.maker.WhereVisitor;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class SelectQueryAction extends QueryAction {

  private Select select;

  private SearchRequestBuilder request;

  public SelectQueryAction(Client client, Select select) {
    super(client, select);
    this.select = select;
  }

  public void intialize(SearchRequestBuilder request) throws MqlParseException {
    this.request = request;
  }

  @Override
  public MqlElasticRequestBuilder explain() throws MqlParseException {
    this.request = client.prepareSearch();
    setIndicesAndTypes();

    setFields(select.getFields());
    setFroms(select.getFrom());
    setWhere(select.getWhere());
    setSorts(select.getOrderBys());
    setLimit(select.getOffset(), select.getRowCount());

    MqlElasticRequestBuilder mqlElasticRequestBuilder = new MqlSearchRequestBuilder(request);

    return mqlElasticRequestBuilder;
  }

  private void setWhere(Where where) throws MqlParseException {
    if (where != null) {
      QueryBuilder query = WhereVisitor.visitWhere(where);
//      QueryBuilder query = QueryMaker.explan(where, this.select.isQuery);
      request.setQuery(query);
    }
  }

  private void setIndicesAndTypes() {
    request.setIndices(query.getIndexArr());

    String[] typeArr = query.getTypeArr();
    if (typeArr != null) {
      request.setTypes(typeArr);
    }
  }

  public void setFields(List<Field> fields) throws MqlParseException {
    if (select.getFields().size() > 0) {
      ArrayList<String> includeFields = new ArrayList<String>();
      ArrayList<String> excludeFields = new ArrayList<String>();

      for (Field field : fields) {
        includeFields.add(field.getName());
      }

      request.setFetchSource(includeFields.toArray(new String[includeFields.size()]), excludeFields.toArray(new String[excludeFields.size()]));
    }
  }

  private void setSorts(List<Order> orderBys) {
    for (Order order : orderBys) {
      request.addSort(order.getName(), SortOrder.valueOf(order.getType()));
    }
  }

  private void setFroms(List<From> froms) {
    String[] indices = froms.stream().map(From::getIndex).collect(Collectors.toList()).toArray(new String[froms.size()]);
    request.setIndices(indices);
  }

  private void setLimit(int from, int size) {
    request.setFrom(from);

    if (size > -1) {
      request.setSize(size);
    }
  }

  public SearchRequestBuilder getRequestBuilder() {
    return request;
  }
}
